--[[
AddonManager by Alleris.

AddonManager helps you keep track of your addons and provides easy ways to access them.

For users:
- Type /addons to see all your registered addons
- Alternatively, click on the AddonManager button in the "Mini Addons" bar 


For addon developers:
- Add a call to AddonManager.RegisterAddon in your VARIABLES_LOADED event
- Example:
    if AddonManager then
        AddonManager.RegisterAddon("MyAddonName", "My addon makes you awesome", 
            "Interface/Addons/MyAddon/myAddon32.tga", "Other", MyAddonConfigFrame, 
            "/myaddon", MyAddonMiniButton)
    else
        Sol.io.Print("My addon's loaded: /myaddon")
    end
    
- Example2: 
    if AddonManager then
        AddonManager.RegisterAddon("MyAddonName", "My addon makes you awesome")
    else
        DEFAULT_CHAT_FRAME:AddMessage("My addon's loaded")
    end
    
- Of course, replace "my addon" with your addon =P
- I recommend not printing out that your addon has loaded if you use addon manager, 
  since the user will be able to see it in the addon manager list.
- In the second example, "My addon" would be considered a "Passive" addon - its
  text would be colored green (like passive skills) and you can't click on it.
  See the AddonManager.RegisterAddon documentation for parameter details.
  
  
- To use a mini-button, you need to first have one created in your xml
- Example:
    <Button name="MyAddonMiniButton" hidden="true" inherits="MinimapButtonTemplate" parent="AddonManagerMiniFrame">
		<Size>
			<AbsDimension y="24" x="24"/>
		</Size>
		<Scripts>
			<OnClick>
                AddonManager.MiniButton_OnClick(this)
			</OnClick>
			<OnEnter>
                AddonManager.MiniButton_OnEnter(this)
			</OnEnter>
			<OnLeave>
				AddonManager.MiniButton_OnLeave(this)
			</OnLeave>
		</Scripts>
	    <NormalTexture file="Interface\AddOns\MyAddon\myAddonIconNormal.tga"/>
	    <PushedTexture file="Interface\AddOns\MyAddon\myAddonIconDown.tga"/>
	</Button>

- The only things you should change here are the Button's name and the two textures.
- Note that you can't have a MiniButton if your addon is passive (because what should happen
  when the user clicks on it?). A passive addon is one that has no config frame and no
  custom onClickScript.
  
--]]


local Sol = LibStub("Sol")


local DEFAULT_ICON = "interface/icons/reci_car_001"
local TAB_ICON_PATH = "Interface/Addons/AddonManager/Textures/"
local SETTINGS_PAGE = 2

AddonManager = {}
AddonManager.Addons = {}
AddonManager.VERSION = "v1.14"

AddonManager.Strata = {
    "BACKGROUND",
    "LOW",
    "MEDIUM",
    "HIGH",
    "DIALOG",
    "TOOLTIP"
}

AddonManager.Categories = {
    "Development",
    "Economy",
    "Information",
    "Interface",
    "Inventory",
    "Leveling",
    "Map",
    "PvP",
    "Social",
    "Other"
}

AddonManager.DefaultSettings = {
    MovePassiveToBack = true,
    ShowMiniBar = true,
    ShowOnlyNamesInMiniBar = true,
    ShowSlashCmdInsteadOfCat = false,
    ShowMiniBarBorder = true,
    ShowMinimapButton = false,
    AutoHideMiniBar = false,
    LockMiniBar = false,
    FrameStrata = 2,
}

AddonManager_UncheckedAddons = {}

local AddonManager_Loaded = false

--[[
Registers an addon with AddonManager. Adds the addon to the addons list and potentially also to the mini-addons-frame.


Parameters:
+ name          - Your addon's name. Default is "[No Name]".
+ description   - A brief (one or two sentence) description of your addon. Something that fits in a tooltip. 
+ icon          - Path to a 32x32 image icon (e.g., "Interface/Addons/AddonManager/Textures/addonManagerIcon32.tga").
                  If no icon is specified, will use default "recipe" icon.
+ category      - One of AddonManager.Categories; will be used for filtering the addons list. Default is "Other".
+ configFrame   - If your addon has a config frame or other frame you want to show when your addon is clicked, use this.
+ slashCommands - Specify any slash commands you've registered so that the user doesn't have to remember them.
+ miniButton    - If you want to display a minimap-style button on the AddonManager "Mini Addons" frame, specify it here.
                  Note that you must have a valid minimap button created in your xml and your addon must not be passive
                  for this to work. See above for details.
+ onClickScript - If you need to special handling when your addon's button is clicked, you can specify a script for it.
                  If this parameter is specified, configFrame is ignored.
+ version       - Your addon's version. To be displayed in the tooltip.
+ author        - Who made this addon.
+ disableScript - A script that can be used to disable your addon. Adds the disable option in the AddonManager list if
                  both disableScript and enableScript are specified
+ enableScript  - A script that can be used to re-enable your addon
--]]
AddonManager.RegisterAddon = function(name, description, icon, category, configFrame, slashCommands, 
    miniButton, onClickScript, version, author, disableScript, enableScript)
    
    local addon = {
        name = name, 
        description = description, 
        icon = icon, 
        category = category,
        configFrame = configFrame, 
        slashCommands = slashCommands, 
        miniButton = miniButton,
        onClickScript = onClickScript,
        version = version,
        author = author,
        disableScript,
        enableScript,
    }
    
    AddonManager.RegisterAddonTable(addon)
end


--[[
Registers an addon with AddonManager. Adds the addon to the addons list and potentially also to the mini-addons-frame.

Parameters:
+ addon - A table of key-value pairs, with the keys being the parameters to AddonManager.RegisterAddon

Example: 
local addon = {
    name = "MyAddon",
    description = "My awesome addon",
    slashCommand = "/myaddon",
    version = "v0.01"
}
--]]
AddonManager.RegisterAddonTable = function(addon)
    --if not AddonManager_Loaded then
    --    return
    --end
    
    
    if not addon or not type(addon) == "table" then
        return
    end

    if not addon.name then 
        addon.name = "[No Name]"
    end
    if not addon.description then
        addon.description = ""
    end
    if not addon.category or not Sol.table.Contains(AddonManager.Categories, addon.category) then
        addon.category = "Other"
    end
    addon.enabled = true
    
    local inserted = false
    for i, v in ipairs(AddonManager.Addons) do
        if AddonManager.AddonSortFn(addon, v) then
            inserted = true
            table.insert(AddonManager.Addons, i, addon)
            break
        end
    end
    if not inserted then
        table.insert(AddonManager.Addons, addon)
    end
    
	if AddonManagerFrame:IsVisible() then
		AddonManager.Update()
	end
    
    if AddonManager_Loaded and addon.miniButton and not AddonManager.IsPassive(addon) then
        AddonManager.AddNewMiniIcon(addon)
    end
end

AddonManager.OnLoad = function(frame)    
	frame:RegisterEvent("VARIABLES_LOADED")
end

AddonManager.OnEvent = function(frame, event, _arg1)
	if event == "VARIABLES_LOADED" then
        AddonManager_Loaded = true
        
		Sol.config.CreateSlashToHandleConfig("AddonManager", AddonManagerFrame, "addons")
        Sol.config.CheckSettings("AddonManager", AddonManager.DefaultSettings)
        Sol.config.SetupDropdown(AddonManagerConfig_DropdownFrameStrata, AddonManager.Strata, AddonManager_Settings.FrameStrata)
        
        local categories = Sol.table.DeepCopy(AddonManager.Categories)
        table.insert(categories, 1, "All")
        Sol.config.SetupDropdown(AddonManagerCategoryFilter, categories, 1, 110, AddonManager.Update)
        
        SaveVariables("AddonManager_UncheckedAddons")
        
        -- Setup tabs
        PanelTemplates_IconTabInit(AddonManagerFrameTabAddons, TAB_ICON_PATH .. "addonsTab2.tga", "All Addons")
        PanelTemplates_IconTabInit(AddonManagerFrameTabSettings, TAB_ICON_PATH .. "settingsTab.tga", "Settings")
        SkillTab_SetActiveState(AddonManagerFrameTabAddons, true)
        SkillTab_SetActiveState(AddonManagerFrameTabSettings, false)
        
        AddonManagerFrame.page = 1
        AddonManagerFrame.tab = AddonManagerFrameTabAddons
        
        -- Set mini position
        if AddonManager_Settings.MiniX then
            local scale = GetUIScale()
            AddonManagerMiniFrame:ClearAllAnchors()
            AddonManagerMiniFrame:SetAnchor("TOPLEFT", "TOPLEFT", "UIParent", 
                AddonManager_Settings.MiniX / scale, 
                AddonManager_Settings.MiniY / scale)
        end
        
        -- Hey, this is an addon, too =D
        local addonMgr = {
            name = "AddonManager",
            version = AddonManager.VERSION,
            author = "Alleris",
            description = "Manages your addons... You're looking at it right now ;)", 
            icon = TAB_ICON_PATH .. "addonManagerIcon32.tga", 
            category = "Information", 
            configFrame = AddonManagerFrame, 
            slashCommand = "/addons", 
            miniButton = AddonManagerMiniButton,
        }
        AddonManager.RegisterAddonTable(addonMgr)
        
        -- Add mini buttons now
        for _, addon in pairs(AddonManager.Addons) do
            if addon ~= addonMgr and addon.miniButton and not AddonManager.IsPassive(addon) then
                AddonManager.AddNewMiniIcon(addon)
            end
        end
        
        AddonManager.RecheckSettings()
    end
end

AddonManager.OnShow = function(frame)
    -- Should already be sorted, unless settings change
    table.sort(AddonManager.Addons, AddonManager.AddonSortFn)
	
    AddonManager.Update()
    Sol.config.LoadConfig("AddonManager")
end

AddonManager.SaveSettings = function(frame)
    Sol.config.SaveConfig("AddonManager")
    
    table.sort(AddonManager.Addons, AddonManager.AddonSortFn)
    AddonManager.Update()
    
    AddonManager.RecheckSettings()
end

AddonManager.RecheckSettings = function()
    AddonManager.ShowOrHideMiniBar(AddonManager_Settings.ShowMiniBar)
	Sol.util.SetVisible(AddonManagerMiniFrameBorder, AddonManager_Settings.ShowMiniBarBorder)
	Sol.util.SetVisible(AddonManagerMinimapButton, AddonManager_Settings.ShowMinimapButton)
    Sol.util.SetVisible(AddonManagerMiniFrame_Corner, not AddonManager_Settings.LockMiniBar)
    AddonManagerMiniFrame:SetFrameStrata(AddonManager.Strata[AddonManager_Settings.FrameStrata])
    
	if AddonManager_Settings.ShowMiniBar then
        if AddonManager_Settings.AutoHideMiniBar then
            AddonManager.MinimizeMiniBar()
        else
            AddonManager.RestoreMiniBar()
        end
    end
end

AddonManager.MinimapButton_OnClick = function(this)
	ToggleUIFrame(AddonManagerFrame)
end

-- If addonA should come before addonB in the addons list, returns true; else false
AddonManager.AddonSortFn = function(addonA, addonB)
    if AddonManager_Settings and not AddonManager_Settings.MovePassiveToBack then
        return addonA.name:lower() < addonB.name:lower()
    else
        local aIsPassive = AddonManager.IsPassive(addonA)
        local bIsPassive = AddonManager.IsPassive(addonB)
        
        if aIsPassive and not bIsPassive then
            -- addonA > addonB 
            return false  
        elseif not aIsPassive and bIsPassive then
            -- addonA < addonB
            return true
        else
            return addonA.name:lower() < addonB.name:lower()
        end            
    end
end

-- Determines if this addon's button should be clickable, the addon's text color, etc
AddonManager.IsPassive = function(addon)
    return addon.configFrame == nil and (addon.onClickScript == nil or not type(addon.onClickScript) == "function")
end

-- Refreshes the addons page
AddonManager.Update = function()
    Sol.util.SetVisible(AddonManagerFramePageAddonsPagingBar, AddonManager.GetNumPages() > 1)
    
        
    for i = 1, DF_MAXPAGESKILL_SKILLBOOK do
        local addon	= AddonManager.GetAddonAtIndex(i)
        local item = _G["AddonManagerAddonButton" .. i]
        if not addon then
            item:Hide()
        else
            local iconFrame = _G["AddonManagerAddonButton" .. i .. "ItemButton"]
            local nameFrame = _G["AddonManagerAddonButton" .. i .. "_AddonInfo_Name"]
            local categoryFrame = _G["AddonManagerAddonButton" .. i .. "_AddonInfo_Category"]
            local miniButtonCheck = _G["AddonManagerAddonButton" .. i .. "MiniCheck"]
            local enabledCheck = _G["AddonManagerAddonButton" .. i .. "EnabledCheck"]
            enabledCheck:ClearAllAnchors()

            item:Show()
            categoryFrame:SetText(Sol.util.TernaryOp(AddonManager_Settings.ShowSlashCmdInsteadOfCat, addon.slashCommands, addon.category))
            SetItemButtonTexture(iconFrame, Sol.util.TernaryOp(addon.icon, addon.icon, DEFAULT_ICON))
            if addon.miniButton then
                miniButtonCheck:Show()
                if not Sol.table.Contains(AddonManager_UncheckedAddons, addon.name) then
                    miniButtonCheck:SetChecked(true)
                else
                    miniButtonCheck:SetChecked(false)
                end
                enabledCheck:SetAnchor("BOTTOMRIGHT", "BOTTOMRIGHT", item, -35, 6)
            else
                miniButtonCheck:Hide()
                enabledCheck:SetAnchor("BOTTOMLEFT", "BOTTOMLEFT", item, -3, 6)
            end
            
            if AddonManager.IsPassive(addon) then
                iconFrame:Disable()
                
                -- "Passive" addon = passive color
                nameFrame:SetText(Sol.color.ColorText(addon.name, "00AA00"))
            else 
                iconFrame:Enable()
                nameFrame:SetText(addon.name)
            end
            
            if addon.disableScript and addon.enableScript then
                enabledCheck:Show()
                enabledCheck:SetChecked(addon.enabled)
            else
                enabledCheck:Hide()
            end
        end
    end
end

AddonManager.OnAddonEntered = function(btn, id)
    local addon = btn.addon  -- used for mini-bar buttons
    
    if not addon and id then -- used for main frame buttons
        addon = AddonManager.GetAddonAtIndex(id)
        _G[btn:GetName() .. "Highlight"]:Show()
    end
    
    GameTooltip:ClearAllAnchors()
	GameTooltip:SetOwner(btn, "ANCHOR_RIGHT", 10, 0)
    
    local name = addon.name
    if addon.version then
        name = name .. " " .. addon.version 
    end
	GameTooltip:SetText(name)
    GameTooltip:AddLine(addon.category, 0.5, 0.5, 0.5)
    GameTooltip:AddLine(Sol.color.ColorText(addon.description, "00AAFF"))
    if addon.slashCommands or addon.author then
        GameTooltip:AddLine(" ")
        if addon.slashCommands then
            GameTooltip:AddLine(Sol.color.ColorText("Slash command: " .. Sol.color.ColorText(addon.slashCommands, "00FF00"), "00AAFF"))
        end
        if addon.author then
            GameTooltip:AddLine("Made by " .. addon.author, 0.5, 0.5, 0.5)
        end
    end
end

AddonManager.OnAddonMiniChecked = function(checkBox, id)
    local addon	= AddonManager.GetAddonAtIndex(id)
    if checkBox:IsChecked() then
        if Sol.table.Contains(AddonManager_UncheckedAddons, addon.name) then
            Sol.table.RemoveValue(AddonManager_UncheckedAddons, addon.name)
        end
        AddonManager.ShowMiniButton(addon)
    else
        table.insert(AddonManager_UncheckedAddons, addon.name)
        AddonManager.HideMiniButton(addon)
    end
end

AddonManager.OnAddonEnabledChecked = function(checkBox, id)
    local addon	= AddonManager.GetAddonAtIndex(id)
    if checkBox:IsChecked() then
        addon.enabled = true
        addon.enableScript()
    else
        addon.enabled = false
        addon.disableScript()
    end
end

AddonManager.OnAddonClicked = function(btn, id)
    local addon	= AddonManager.GetAddonAtIndex(id)
    if addon.onClickScript then
        addon.onClickScript(btn, id)
        
    elseif Sol.util.IsValidFrame(addon.configFrame) then
        ToggleUIFrame(addon.configFrame)
        GameTooltip:Hide()
    end
end

AddonManager.OnTabClicked = function(tab, id)
    SkillTab_SetActiveState(AddonManagerFrame.tab, false)
    SkillTab_SetActiveState(tab, true)
    AddonManagerFrame.tab = tab
    if id == 1 then
        AddonManager.Update()
        AddonManagerFramePageAddons:Show()
        AddonManagerFramePageSettings:Hide()
    else
        AddonManagerFramePageAddons:Hide()
        AddonManagerFramePageSettings:Show()
    end
end

AddonManager.TurnPageBack = function(btn)
    AddonManagerFrame.page = AddonManagerFrame.page - 1
    if AddonManagerFrame.page == 1 then
        btn:Hide()
    end
    AddonManagerFramePageAddonsPagingBarRightPage:Show()
    AddonManager.Update()
end

AddonManager.TurnPageForward = function(btn)
    AddonManagerFrame.page = AddonManagerFrame.page + 1
    if AddonManagerFrame.page >= AddonManager.GetNumPages() then
        btn:Hide()
    end
    AddonManagerFramePageAddonsPagingBarLeftPage:Show()
    AddonManager.Update()
end

-- There's only DF_MAXPAGESKILL_SKILLBOOK per page; when switching pages we merely
-- change what's displayed there. The IDs stay the same, so we need to take into
-- account what page we're on
AddonManager.GetAddonAtIndex = function(id)
    local num = (AddonManagerFrame.page - 1) * DF_MAXPAGESKILL_SKILLBOOK + id
    
    local filter = UIDropDownMenu_GetSelectedID(AddonManagerCategoryFilter)
    if filter == 1 then  -- All
        return AddonManager.Addons[num]
    else
        filter = AddonManager.Categories[filter - 1]
        local count = 1
        for _, addon in pairs(AddonManager.Addons) do
            if addon.category == filter then
                count = count + 1
                if count > num then
                    return addon
                end
            end
        end
    end
end

-- How many pages are needed for the # of addons that are registered?
AddonManager.GetNumPages = function()
    return math.ceil(#AddonManager.Addons / DF_MAXPAGESKILL_SKILLBOOK)
end
